#include "qelib.h"
#include "gxcp.h"
#include "udp_socket.h"



#define TEST_LOG_DOMAIN     "test"
#define test_debug(...)     qelog_debug(TEST_LOG_DOMAIN, __VA_ARGS__)
#define test_info(...)      qelog_info(TEST_LOG_DOMAIN, __VA_ARGS__)
#define test_notice(...)    qelog_notice(TEST_LOG_DOMAIN, __VA_ARGS__)
#define test_warning(...)   qelog_warning(TEST_LOG_DOMAIN, __VA_ARGS__)
#define test_error(...)     qelog_error(TEST_LOG_DOMAIN, __VA_ARGS__)
#define test_hexdump(...)   qehex_debug(TEST_LOG_DOMAIN, __VA_ARGS__)




typedef struct
{
    udp_socket sock;
    SOCKADDR_IN host_addr;
} gxcp_udp_test;

static qe_const_str usages[] = {
    "gxcp-test [options] [[--] args]",
    "gxcp-test [options]",
    QE_NULL,
};

static qe_int udp_read(qe_u8 *data, qe_size size, void *user)
{
    SOCKADDR_IN addr;
    gxcp_udp_test *test = (gxcp_udp_test *)user;
    return udp_socket_recv(&test->sock, (char *)data, size, &addr);
}

static qe_int udp_write(qe_u8 *data, qe_size size, void *user)
{
    gxcp_udp_test *test = (gxcp_udp_test *)user;
    return udp_socket_send(&test->sock, (char *)data, size, &test->host_addr);
}

static gxcp_ret readmem_callback(qe_u32 addr, qe_u8 *data, qe_size size, void *user)
{
    test_info("readmem addr:0x%x len:%d", addr, size);
    return GXCP_SUCCESS;
}

static gxcp_ret writemem_callback(qe_u32 addr, qe_u8 *data, qe_size size, void *user)
{
    test_debug("writemem addr:0x%x len:%d", addr, size);
    test_hexdump(data, size);
    return GXCP_SUCCESS;
}

int main(int argc, char **argv)
{
    int rxlen;
    char buffer[1500];
    qe_ret ret;
    qe_int port = 6009;
    qe_str addr = "192.168.1.100";
    gxcp_io udp_io;
    gxcp_callback callback;
    gxcp_ctx gxcp;
    gxcp_bootstrap_regs bsr;
    gxcp_udp_test test;
    SOCKADDR_IN bind_addr;
    qe_argparse parser;

    qelog_init(QELOG_INFO, QELOG_DM|QELOG_HMS|QELOG_CL|QELOG_LV);

    qe_option options[] = {
        
        QE_OPT_STRING('a', "addr", "bind local address", &addr),
        QE_OPT_INTEGER('p', "port", "bind local port", &port),

        QE_OPT_HELP('h', "help", "Help message"),
        QE_OPT_END(),
    };

    qe_argp_init(&parser, options, usages,
        "\nGXCP Testing.",
        "\nGXCP Testing.");
    ret = qe_argp_parse(&parser, argc, (qe_const_str *)argv);
    if (ret != qe_ok) {
        return -1;
    }

    bind_addr.sin_family = AF_INET;
    bind_addr.sin_addr.s_addr = inet_addr(addr);
    bind_addr.sin_port = qe_htons(port);
    udp_socket_init(&test.sock);
    udp_socket_bind(&test.sock, &bind_addr);
    udp_socket_set_timeout(&test.sock, 1000);

    udp_io.read = udp_read;
    udp_io.write = udp_write;
    callback.readmem = readmem_callback;
    callback.writemem = writemem_callback;

    qe_memset(&bsr, 0, sizeof(bsr));
    bsr.protocol_version = 0x00010000;
    qe_sprintf(bsr.manufacturer_name, "Weistudio");
    qe_sprintf(bsr.model_name, "GCMP-Testing");
    qe_sprintf(bsr.device_version, "AAA");
    qe_sprintf(bsr.serial_number, "132567653");
    qe_sprintf(bsr.device_version, "01.00.00");
    bsr.device_capability = 1;
    bsr.max_dev_response_time = 1000;

    gxcp_init(&gxcp, 4096, &test);
    gxcp_set_io(&gxcp, &udp_io);
    gxcp_set_callback(&gxcp, &callback);
    gxcp_set_bootstrap(&gxcp, &bsr);

    test_info("start recv");

    while (1) {
        rxlen = udp_socket_recv(&test.sock, buffer, 1500, 
            &test.host_addr);
        if (rxlen > 0) {
            gxcp_rx_handle(&gxcp, buffer, rxlen);
        }
    }
}